package com.kinyx.framework.db.daos;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;

import com.kinyx.framework.annotation.assist.CanNotNull;
import com.kinyx.framework.annotation.assist.CanNull;
import com.kinyx.framework.annotation.assist.Note;
import com.kinyx.framework.annotation.assist.ReturnNotNull;
import com.kinyx.framework.annotation.assist.Throws;
import com.kinyx.framework.db.configs.DBConfigs;
import com.kinyx.framework.db.vo.ColumnInfo;
import com.kinyx.framework.enums.impl.ErrorCode1;
import com.kinyx.framework.exception.KRuntimeException;
import com.kinyx.framework.function.Handler;
import com.kinyx.framework.reflect.KBeanUtils;
import com.kinyx.framework.reflect.KFieldUtils;
import com.kinyx.framework.reflect.KTypeConverter;

/**
 * JDBC工具类
 */
public class JDBCTool {

	/**
	 * 建立连接
	 * @param jdbcUrl 连接地址
	 * @param username 用户名
	 * @param password 密码
	 * @return 连接
	 */
	@Throws(at = "JDBCTool.getConnection(String, String, String)", value = "ErrorCode1.CODE_ERROR_101", when = "DriverManager.getConnection(String, String, String)")
	@ReturnNotNull
	public static Connection getConnection(@CanNotNull final String jdbcUrl, @CanNotNull final String username, @CanNotNull final String password) {
		try {
			return DriverManager.getConnection(jdbcUrl, username, password);
		} catch (final SQLException e) {
			throw new KRuntimeException(e, ErrorCode1.CODE_ERROR_101).param("jdbcUrl", jdbcUrl).param("username", username).param("password", password);
		}
	}

	/**
	 * 关闭连接对象
	 * @param connection 连接对象
	 */
	@Note("exception ignored")
	public static void closeConnection(@CanNull final Connection connection) {
		try {
			// 关闭连接
			if (connection != null) { connection.close(); }
		} catch (final SQLException ex) {} // ignore this
	}

	private static RuntimeException closeConnectionAndThrowException(@CanNull final Connection connection, //
			@CanNull final Handler beforeCloseConnection, //
			@CanNull final Consumer<RuntimeException> afterCloseConnection, //
			final RuntimeException e) {
		// 关闭连接之前的操作方法
		if (beforeCloseConnection != null) { beforeCloseConnection.handle(); }
		// 关闭连接
		closeConnection(connection);
		// 关闭连接之后的操作方法
		if (afterCloseConnection != null) { afterCloseConnection.accept(e); }
		// 返回异常
		return e;
	}

	@Throws(at = "JDBCTool.newTransaction(Connection)", value = "ErrorCode1.CODE_ERROR_109", when = "Connection.setAutoCommit(false)")
	private static void newTransaction(@CanNotNull final Connection connection) {
		try {
			// 开启事务
			connection.setAutoCommit(false);
		} catch (final SQLException e) {
			// 转换为运行时异常
			throw new KRuntimeException(e, ErrorCode1.CODE_ERROR_109);
		}
	}

	/**
	 * 开启事务
	 * @param connection 连接对象
	 * @param beforeCloseConnection 发生异常时，关闭连接之前的操作方法。
	 * @param afterCloseConnection 发生异常时，关闭连接之后的操作方法。
	 */
	@Note("already closed Connection when throwing exception")
	@Throws(at = "JDBCTool.newTransaction(Connection)", value = "ErrorCode1.CODE_ERROR_109", when = "Connection.setAutoCommit(false)")
	public static void newTransaction(@CanNotNull final Connection connection, //
			@CanNull final Handler beforeCloseConnection, //
			@CanNull final Consumer<RuntimeException> afterCloseConnection) {
		try {
			newTransaction(connection);
		} catch (final RuntimeException e) {
			throw closeConnectionAndThrowException(connection, beforeCloseConnection, afterCloseConnection, e);
		}
	}

	/**
	 * 回滚事务
	 * @param connection 连接对象
	 */
	@Note("exception ignored")
	public static void rollback(@CanNotNull final Connection connection) {
		try {
			connection.rollback();
		} catch (final SQLException ex) {} // ignore this
	}

	/**
	 * 提交事务
	 * @param connection 连接对象
	 */
	@Throws(at = "JDBCTool.commitTransaction(Connection)", value = "ErrorCode1.CODE_ERROR_110", when = "Connection.commit()")
	private static void commitTransaction(@CanNotNull final Connection connection) {
		try {
			// 提交事务
			connection.commit();
		} catch (final SQLException e) {
			throw new KRuntimeException(e, ErrorCode1.CODE_ERROR_110);
		}
	}

	/**
	 * 提交事务
	 * @param connection 连接对象
	 * @param beforeCloseConnection 发生异常时，关闭连接之前的操作方法。
	 * @param afterCloseConnection 发生异常时，关闭连接之后的操作方法。
	 */
	@Note("already closed Connection when throwing exception")
	@Throws(at = "JDBCTool.commitTransaction(Connection)", value = "ErrorCode1.CODE_ERROR_110", when = "Connection.commit()")
	public static void commitTransaction(@CanNotNull final Connection connection, //
			@CanNull final Handler beforeCloseConnection, //
			@CanNull final Consumer<RuntimeException> afterCloseConnection) {
		try {
			commitTransaction(connection);
		} catch (final RuntimeException e) {
			throw closeConnectionAndThrowException(connection, beforeCloseConnection, afterCloseConnection, e);
		}
	}

	/**
	 * 创建语句对象
	 * @param connection 连接对象
	 * @param sql 语句
	 * @param params 参数
	 * @return 语句对象
	 */
	@Note("already closed PreparedStatement when throwing exception")
	@Throws(at = "JDBCTool.prepareStatement(Connection, String, List<Object>)", value = "ErrorCode1.CODE_ERROR_102", when = "Connection.prepareStatement(String)")
	@Throws(at = "JDBCTool.prepareStatement(Connection, String, List<Object>)", value = "ErrorCode1.CODE_ERROR_103", when = "PreparedStatement.setObject(int, Object)")
	@ReturnNotNull
	private static PreparedStatement prepareStatement(@CanNotNull final Connection connection, @CanNotNull final String sql, @CanNull final List<Object> params) {
		// 创建语句对象
		PreparedStatement ps;
		try {
			ps = connection.prepareStatement(sql);
		} catch (final SQLException e) {
			throw new KRuntimeException(e, ErrorCode1.CODE_ERROR_102).param("sql", sql);
		}

		// 设置参数
		if (params != null) {
			int parameterIndex = 0;
			Object param = null;
			try {
				for (int i = 0; i < params.size(); i++) {
					param = params.get(i);
					parameterIndex = i + 1;
					if (param == null) {
						ps.setObject(parameterIndex, null);
					} else {
						if (param.getClass().isEnum()) {// 枚举类型转为字符串类型
							ps.setObject(parameterIndex, param.toString());
						} else {
							ps.setObject(parameterIndex, param);
						}
					}
				}
			} catch (final SQLException e) {
				// 关闭语句
				closeStatement(ps);
				// 转换为运行时异常
				throw new KRuntimeException(e, ErrorCode1.CODE_ERROR_103).param("parameterIndex", parameterIndex).param("param", param);
			}
		}
		return ps;
	}

	/**
	 * 创建语句对象
	 * @param connection 连接对象
	 * @param sql 语句
	 * @param params 参数
	 * @param beforeCloseConnection 发生异常时，关闭连接之前的操作方法。
	 * @param afterCloseConnection 发生异常时，关闭连接之后的操作方法。
	 * @return 语句对象
	 */
	@Note("already closed PreparedStatement when throwing exception")
	@Note("already closed Connection when throwing exception")
	@Throws(at = "JDBCTool.prepareStatement(Connection, String, List<Object>)", value = "ErrorCode1.CODE_ERROR_102", when = "Connection.prepareStatement(String)")
	@Throws(at = "JDBCTool.prepareStatement(Connection, String, List<Object>)", value = "ErrorCode1.CODE_ERROR_103", when = "PreparedStatement.setObject(int, Object)")
	@ReturnNotNull
	public static PreparedStatement prepareStatement(@CanNotNull final Connection connection, @CanNotNull final String sql, @CanNull final List<Object> params, //
			@CanNull final Handler beforeCloseConnection, //
			@CanNull final Consumer<RuntimeException> afterCloseConnection) {
		try {
			return prepareStatement(connection, sql, params);
		} catch (final RuntimeException e) {
			throw closeConnectionAndThrowException(connection, beforeCloseConnection, afterCloseConnection, e);
		}
	}

	/**
	 * 设置查询结果最大值
	 * @param ps 语句对象
	 * @param maxCount 查询结果最大数量
	 */
	@Note("already closed PreparedStatement when throwing exception")
	@Throws(at = "JDBCTool.prepareStatement(PreparedStatement, int)", value = "ErrorCode1.CODE_ERROR_113", when = "PreparedStatement.setMaxRows(int)")
	private static void setMaxRows(@CanNotNull final PreparedStatement ps, @CanNotNull final int maxCount) {
		// 设置查询结果最大值
		if (maxCount > 0) {
			try {
				ps.setMaxRows(maxCount);
			} catch (final SQLException e) {
				// 关闭语句
				closeStatement(ps);
				// 抛出异常
				throw new KRuntimeException(e, ErrorCode1.CODE_ERROR_113).param("maxCount", maxCount);
			}
		}
	}

	/**
	 * 设置查询结果最大值
	 * @param connection 连接对象
	 * @param ps 语句对象
	 * @param maxCount 查询结果最大数量
	 * @param beforeCloseConnection 发生异常时，关闭连接之前的操作方法。
	 * @param afterCloseConnection 发生异常时，关闭连接之后的操作方法。
	 */
	@Note("already closed PreparedStatement when throwing exception")
	@Note("already closed Connection when throwing exception")
	@Throws(at = "JDBCTool.prepareStatement(PreparedStatement, int)", value = "ErrorCode1.CODE_ERROR_113", when = "PreparedStatement.setMaxRows(int)")
	public static void setMaxRows(@CanNotNull final Connection connection, @CanNotNull final PreparedStatement ps, @CanNotNull final int maxCount, //
			@CanNull final Handler beforeCloseConnection, //
			@CanNull final Consumer<RuntimeException> afterCloseConnection) {
		try {
			setMaxRows(ps, maxCount);
		} catch (final RuntimeException e) {
			throw closeConnectionAndThrowException(connection, beforeCloseConnection, afterCloseConnection, e);
		}
	}

	/**
	 * 关闭语句对象
	 * @param ps 语句对象
	 */
	@Note("exception ignored")
	public static void closeStatement(@CanNull final PreparedStatement ps) {
		try {
			if (ps != null) { ps.close(); }
		} catch (final SQLException e) {} // ignore this
	}

	/**
	 * 执行查询
	 * @param ps 语句对象
	 * @return 结果集
	 */
	@Note("already closed PreparedStatement when throwing exception")
	@Throws(at = "JDBCTool.executeQuery(PreparedStatement)", value = "ErrorCode1.CODE_ERROR_107", when = "PreparedStatement.executeQuery()")
	@ReturnNotNull
	private static ResultSet executeQuery(@CanNotNull final PreparedStatement ps) {
		try {
			// 执行查询
			final ResultSet rs = ps.executeQuery();
			// 返回结果
			return rs;
		} catch (final SQLException e) {
			// 关闭语句
			closeStatement(ps);
			// 抛出异常
			throw new KRuntimeException(e, ErrorCode1.CODE_ERROR_107);
		}
	}

	/**
	 * 执行查询
	 * @param connection 连接对象
	 * @param ps 语句对象
	 * @param beforeCloseConnection 发生异常时，关闭连接之前的操作方法。
	 * @param afterCloseConnection 发生异常时，关闭连接之后的操作方法。
	 * @return 结果集
	 */
	@Note("already closed PreparedStatement after execution")
	@Note("already closed PreparedStatement when throwing exception")
	@Note("already closed Connection when throwing exception")
	@Throws(at = "JDBCTool.executeQuery(PreparedStatement)", value = "ErrorCode1.CODE_ERROR_107", when = "PreparedStatement.executeQuery()")
	@ReturnNotNull
	public static ResultSet executeQuery(@CanNotNull final Connection connection, @CanNotNull final PreparedStatement ps, //
			@CanNull final Handler beforeCloseConnection, //
			@CanNull final Consumer<RuntimeException> afterCloseConnection) {
		try {
			return executeQuery(ps);
		} catch (final RuntimeException e) {
			throw closeConnectionAndThrowException(connection, beforeCloseConnection, afterCloseConnection, e);
		}
	}

	/**
	 * 关闭结果集对象
	 * @param rs 结果集对象
	 */
	@Note("exception ignored")
	public static void closeResultSet(@CanNull final ResultSet rs) {
		try {
			if (rs != null) { rs.close(); }
		} catch (final SQLException e) {} // ignore this
	}

	@Throws(at = "JDBCTool.columnInfos(Class, ResultSet)", value = "ErrorCode1.CODE_ERROR_104", when = "ResultSet.getMetaData()")
	@Throws(at = "JDBCTool.columnInfos(Class, ResultSet)", value = "ErrorCode1.CODE_ERROR_105", when = "ResultSetMetaData.getColumnCount()")
	@Throws(at = "JDBCTool.columnInfos(Class, ResultSet)", value = "ErrorCode1.CODE_ERROR_106", when = "ResultSetMetaData.getColumnName(int)")
	private static <B> List<ColumnInfo> columnInfos(final Class<B> clazz, final ResultSet rs, final DBConfigs configs) {
		// 获取结果集信息
		ResultSetMetaData rsmd;
		try {
			rsmd = rs.getMetaData();
		} catch (final SQLException e) {
			// 抛出异常
			throw new KRuntimeException(e, ErrorCode1.CODE_ERROR_104);
		}
		// 获取查询结果列数
		int columnCount;
		try {
			columnCount = rsmd.getColumnCount();
		} catch (final SQLException e) {
			// 抛出异常
			throw new KRuntimeException(e, ErrorCode1.CODE_ERROR_105);
		}

		// 创建字段列表
		final List<ColumnInfo> columnInfos = configs.getColumnInfos(clazz);
		final List<ColumnInfo> mappedColumnInfos = new ArrayList<>(columnCount);
		// 按照结果集顺序设置对应的字段列表
		out: for (int column = 1; column <= columnCount; column++) {
			String columnName;
			try {
				columnName = rsmd.getColumnName(column);
			} catch (final SQLException e) {
				throw new KRuntimeException(e, ErrorCode1.CODE_ERROR_106).param("column", column);
			}
			// 和查询结果映射字段名一致的加入列表，否则将null值加入列表。
			for (final ColumnInfo columnInfo : columnInfos) {
				if (columnInfo.getColumnName().equals(columnName)) {
					mappedColumnInfos.add(columnInfo);
					continue out;
				}
			}
			mappedColumnInfos.add(null);
		}
		return mappedColumnInfos;
	}

	@Throws(at = "JDBCTool.newInstance(Class, ResultSet, List)", value = "ErrorCode1.CODE_ERROR_111", when = "ResultSet.getObject(int)")
	private static <B> B newInstance(final Class<B> clazz, final ResultSet rs, final List<ColumnInfo> columnInfos) {
		// 创建实例对象
		final B bean = KBeanUtils.newInstance(clazz);
		// 设置字段值
		for (int col = 0; col < columnInfos.size(); col++) {
			final ColumnInfo columnInfo = columnInfos.get(col);
			if (columnInfo != null) {
				final int columnIndex = col + 1;
				Object obj;
				try {
					obj = rs.getObject(columnIndex);
				} catch (final SQLException e) {
					throw new KRuntimeException(e, ErrorCode1.CODE_ERROR_111).param("columnIndex", columnIndex);
				}
				KFieldUtils.set(bean, columnInfo.getField(), obj);
			}
		}
		// 返回实例
		return bean;
	}

	@Throws(at = "JDBCTool.toValue(Class, ResultSet)", value = "ErrorCode1.CODE_ERROR_104", when = "ResultSet.getMetaData()")
	@Throws(at = "JDBCTool.toValue(Class, ResultSet)", value = "ErrorCode1.CODE_ERROR_105", when = "ResultSetMetaData.getColumnCount()")
	@Throws(at = "JDBCTool.toValue(Class, ResultSet)", value = "ErrorCode1.CODE_ERROR_111", when = "ResultSet.getObject(int)")
	@Throws(at = "JDBCTool.toValue(Class, ResultSet)", value = "ErrorCode1.CODE_ERROR_112", when = "ResultSet.next()")
	@Throws(at = "JDBCTool.toValue(Class, ResultSet)", value = "ErrorCode1.CODE_ERROR_801", when = "ResultSetMetaData.getColumnCount()")
	@Throws(at = "JDBCTool.toValue(Class, ResultSet)", value = "ErrorCode1.CODE_ERROR_802", when = "ResultSet.next()")
	private static <V> V toValue(final Class<V> clazz, final ResultSet rs) {
		// 获取结果集信息
		ResultSetMetaData rsmd;
		try {
			rsmd = rs.getMetaData();
		} catch (final SQLException e) {
			// 抛出异常
			throw new KRuntimeException(e, ErrorCode1.CODE_ERROR_104);
		}
		// 获取查询结果列数
		int columnCount;
		try {
			columnCount = rsmd.getColumnCount();
		} catch (final SQLException e) {
			// 抛出异常
			throw new KRuntimeException(e, ErrorCode1.CODE_ERROR_105);
		}

		// 查询结果列数有误
		if (columnCount != 1) { throw new KRuntimeException(ErrorCode1.CODE_ERROR_801); }

		try {
			// 有结果遍历结果集
			if (rs.next()) {
				// 取结果
				Object obj;
				try {
					obj = rs.getObject(1);
				} catch (final SQLException e) {
					// 抛出异常
					throw new KRuntimeException(e, ErrorCode1.CODE_ERROR_111).param("columnIndex", 1);
				}
				// 多条结果验证
				if (rs.next()) {
					// 抛出异常
					throw new KRuntimeException(ErrorCode1.CODE_ERROR_802);
				}
				// 转换结果
				return KTypeConverter.convert(obj, clazz);
			}
			// 没有结果则返回null
			return null;
		} catch (final SQLException e) {
			// 抛出异常
			throw new KRuntimeException(e, ErrorCode1.CODE_ERROR_112);
		}
	}

	/**
	 * 将结果集转换为单个值
	 * @param <V> 泛型
	 * @param connection 连接对象
	 * @param clazz 返回值类型
	 * @param ps 语句对象
	 * @param rs 结果集
	 * @param beforeCloseConnection 发生异常时，关闭连接之前的操作方法。
	 * @param afterCloseConnection 发生异常时，关闭连接之后的操作方法。
	 * @return 单个值
	 */
	@Note("already closed PreparedStatement after execution")
	@Note("already closed PreparedStatement when throwing exception")
	@Note("already closed ResultSet after execution")
	@Note("already closed ResultSet when throwing exception")
	@Note("already closed Connection when throwing exception")
	@Throws(at = "JDBCTool.toValue(Class, ResultSet)", value = "ErrorCode1.CODE_ERROR_104", when = "ResultSet.getMetaData()")
	@Throws(at = "JDBCTool.toValue(Class, ResultSet)", value = "ErrorCode1.CODE_ERROR_105", when = "ResultSetMetaData.getColumnCount()")
	@Throws(at = "JDBCTool.toValue(Class, ResultSet)", value = "ErrorCode1.CODE_ERROR_111", when = "ResultSet.getObject(int)")
	@Throws(at = "JDBCTool.toValue(Class, ResultSet)", value = "ErrorCode1.CODE_ERROR_112", when = "ResultSet.next()")
	@Throws(at = "JDBCTool.toValue(Class, ResultSet)", value = "ErrorCode1.CODE_ERROR_801", when = "ResultSetMetaData.getColumnCount()")
	@Throws(at = "JDBCTool.toValue(Class, ResultSet)", value = "ErrorCode1.CODE_ERROR_802", when = "ResultSet.next()")
	public static <V> V toValue(@CanNotNull final Connection connection, final Class<V> clazz, @CanNotNull final PreparedStatement ps, final ResultSet rs, //
			@CanNull final Handler beforeCloseConnection, //
			@CanNull final Consumer<RuntimeException> afterCloseConnection) {
		try {
			// 转换结果
			final V value = toValue(clazz, rs);
			// 关闭语句
			closeStatement(ps);
			// 关闭结果集
			closeResultSet(rs);
			// 返回结果
			return value;
		} catch (final RuntimeException e) {
			// 关闭语句
			closeStatement(ps);
			// 关闭结果集
			closeResultSet(rs);
			// 关闭连接
			throw closeConnectionAndThrowException(connection, beforeCloseConnection, afterCloseConnection, e);
		}
	}

	@Throws(at = "JDBCTool.columnInfos(Class, ResultSet)", value = "ErrorCode1.CODE_ERROR_104", when = "ResultSet.getMetaData()")
	@Throws(at = "JDBCTool.columnInfos(Class, ResultSet)", value = "ErrorCode1.CODE_ERROR_105", when = "ResultSetMetaData.getColumnCount()")
	@Throws(at = "JDBCTool.columnInfos(Class, ResultSet)", value = "ErrorCode1.CODE_ERROR_106", when = "ResultSetMetaData.getColumnName(int)")
	@Throws(at = "JDBCTool.newInstance(Class, ResultSet, List)", value = "ErrorCode1.CODE_ERROR_111", when = "ResultSet.getObject(int)")
	@Throws(at = "JDBCTool.toList(Class, ResultSet)", value = "ErrorCode1.CODE_ERROR_112", when = "ResultSet.next()")
	private static <B> List<B> toList(final Class<B> clazz, final ResultSet rs, final DBConfigs configs) {
		// 映射列信息
		final List<ColumnInfo> columnInfos = columnInfos(clazz, rs, configs);
		try {
			// 创建结果
			final List<B> listBean = new ArrayList<>();
			// 有结果遍历结果集
			while (rs.next()) {
				// 创建实例
				final B bean = newInstance(clazz, rs, columnInfos);
				// 加入结果列表
				listBean.add(bean);
			}
			// 返回结果
			return listBean;
		} catch (final SQLException e) {
			// 抛出异常
			throw new KRuntimeException(e, ErrorCode1.CODE_ERROR_112);
		}
	}

	/**
	 * 将结果集转换为列表数据
	 * @param <B> 泛型
	 * @param connection 连接对象
	 * @param clazz 返回值类型
	 * @param ps 语句对象
	 * @param rs 结果集
	 * @param beforeCloseConnection 发生异常时，关闭连接之前的操作方法。
	 * @param afterCloseConnection 发生异常时，关闭连接之后的操作方法。
	 * @param configs 数据库配置
	 * @return 列表数据
	 */
	@Note("already closed PreparedStatement after execution")
	@Note("already closed PreparedStatement when throwing exception")
	@Note("already closed ResultSet after execution")
	@Note("already closed ResultSet when throwing exception")
	@Note("already closed Connection when throwing exception")
	@Throws(at = "JDBCTool.columnInfos(Class, ResultSet)", value = "ErrorCode1.CODE_ERROR_104", when = "ResultSet.getMetaData()")
	@Throws(at = "JDBCTool.columnInfos(Class, ResultSet)", value = "ErrorCode1.CODE_ERROR_105", when = "ResultSetMetaData.getColumnCount()")
	@Throws(at = "JDBCTool.columnInfos(Class, ResultSet)", value = "ErrorCode1.CODE_ERROR_106", when = "ResultSetMetaData.getColumnName(int)")
	@Throws(at = "JDBCTool.newInstance(Class, ResultSet, List)", value = "ErrorCode1.CODE_ERROR_111", when = "ResultSet.getObject(int)")
	@Throws(at = "JDBCTool.toList(Class, ResultSet)", value = "ErrorCode1.CODE_ERROR_112", when = "ResultSet.next()")
	public static <B> List<B> toList(@CanNotNull final Connection connection, final Class<B> clazz, @CanNotNull final PreparedStatement ps, final ResultSet rs, //
			@CanNull final Handler beforeCloseConnection, //
			@CanNull final Consumer<RuntimeException> afterCloseConnection, final DBConfigs configs) {
		try {
			// 转换结果
			final List<B> listBean = toList(clazz, rs, configs);
			// 关闭语句
			closeStatement(ps);
			// 关闭结果集
			closeResultSet(rs);
			// 返回结果
			return listBean;
		} catch (final RuntimeException e) {
			// 关闭语句
			closeStatement(ps);
			// 关闭结果集
			closeResultSet(rs);
			// 关闭连接
			throw closeConnectionAndThrowException(connection, beforeCloseConnection, afterCloseConnection, e);
		}
	}

	@Throws(at = "JDBCTool.columnInfos(Class, ResultSet)", value = "ErrorCode1.CODE_ERROR_104", when = "ResultSet.getMetaData()")
	@Throws(at = "JDBCTool.columnInfos(Class, ResultSet)", value = "ErrorCode1.CODE_ERROR_105", when = "ResultSetMetaData.getColumnCount()")
	@Throws(at = "JDBCTool.columnInfos(Class, ResultSet)", value = "ErrorCode1.CODE_ERROR_106", when = "ResultSetMetaData.getColumnName(int)")
	@Throws(at = "JDBCTool.newInstance(Class, ResultSet, List)", value = "ErrorCode1.CODE_ERROR_111", when = "ResultSet.getObject(int)")
	@Throws(at = "JDBCTool.toOne(Class, ResultSet)", value = "ErrorCode1.CODE_ERROR_112", when = "ResultSet.next()")
	@Throws(at = "JDBCTool.toOne(Class, ResultSet)", value = "ErrorCode1.CODE_ERROR_802", when = "ResultSet.next()")
	private static <B> B toOne(final Class<B> clazz, final ResultSet rs, final DBConfigs configs) {
		// 映射列信息
		final List<ColumnInfo> columnInfos = columnInfos(clazz, rs, configs);
		try {
			// 有结果遍历结果集
			if (rs.next()) {
				// 创建实例
				final B bean = newInstance(clazz, rs, columnInfos);
				// 多条结果验证
				if (rs.next()) {
					// 抛出异常
					throw new KRuntimeException(ErrorCode1.CODE_ERROR_802);
				}
				// 返回结果
				return bean;
			}
			// 没有结果则返回null
			return null;
		} catch (final SQLException e) {
			// 抛出异常
			throw new KRuntimeException(e, ErrorCode1.CODE_ERROR_112);
		}
	}

	/**
	 * 将结果集转换为单个数据
	 * @param <B> 泛型
	 * @param connection 连接对象
	 * @param clazz 返回值类型
	 * @param ps 语句对象
	 * @param rs 结果集
	 * @param beforeCloseConnection 发生异常时，关闭连接之前的操作方法。
	 * @param afterCloseConnection 发生异常时，关闭连接之后的操作方法。
	 * @param configs 数据库配置
	 * @return 单个数据
	 */
	@Note("already closed PreparedStatement after execution")
	@Note("already closed PreparedStatement when throwing exception")
	@Note("already closed ResultSet after execution")
	@Note("already closed ResultSet when throwing exception")
	@Note("already closed Connection when throwing exception")
	@Throws(at = "JDBCTool.columnInfos(Class, ResultSet)", value = "ErrorCode1.CODE_ERROR_104", when = "ResultSet.getMetaData()")
	@Throws(at = "JDBCTool.columnInfos(Class, ResultSet)", value = "ErrorCode1.CODE_ERROR_105", when = "ResultSetMetaData.getColumnCount()")
	@Throws(at = "JDBCTool.columnInfos(Class, ResultSet)", value = "ErrorCode1.CODE_ERROR_106", when = "ResultSetMetaData.getColumnName(int)")
	@Throws(at = "JDBCTool.newInstance(Class, ResultSet, List)", value = "ErrorCode1.CODE_ERROR_111", when = "ResultSet.getObject(int)")
	@Throws(at = "JDBCTool.toOne(Class, ResultSet)", value = "ErrorCode1.CODE_ERROR_112", when = "ResultSet.next()")
	@Throws(at = "JDBCTool.toOne(Class, ResultSet)", value = "ErrorCode1.CODE_ERROR_802", when = "ResultSet.next()")
	public static <B> B toOne(@CanNotNull final Connection connection, final Class<B> clazz, @CanNotNull final PreparedStatement ps, final ResultSet rs, //
			@CanNull final Handler beforeCloseConnection, //
			@CanNull final Consumer<RuntimeException> afterCloseConnection, final DBConfigs configs) {
		try {
			// 转换结果
			final B bean = toOne(clazz, rs, configs);
			// 关闭语句
			closeStatement(ps);
			// 关闭结果集
			closeResultSet(rs);
			// 返回结果
			return bean;
		} catch (final RuntimeException e) {
			// 关闭语句
			closeStatement(ps);
			// 关闭结果集
			closeResultSet(rs);
			// 关闭连接
			throw closeConnectionAndThrowException(connection, beforeCloseConnection, afterCloseConnection, e);
		}
	}

	@Note("already closed PreparedStatement after execution")
	@Note("already closed PreparedStatement when throwing exception")
	@Throws(at = "JDBCTool.executeUpdate(PreparedStatement)", value = "ErrorCode1.CODE_ERROR_108", when = "PreparedStatement.executeUpdate()")
	@ReturnNotNull
	private static int executeUpdate(@CanNotNull final PreparedStatement ps) {
		try {
			// 执行更新
			final int result = ps.executeUpdate();
			// 关闭语句
			closeStatement(ps);
			// 返回结果
			return result;
		} catch (final SQLException e) {
			// 关闭语句
			closeStatement(ps);
			// 抛出异常
			throw new KRuntimeException(e, ErrorCode1.CODE_ERROR_108);
		}
	}

	/**
	 * 执行更新
	 * @param connection 连接对象
	 * @param ps 语句对象
	 * @param beforeCloseConnection 发生异常时，关闭连接之前的操作方法。
	 * @param afterCloseConnection 发生异常时，关闭连接之后的操作方法。
	 * @return 影响的结果数
	 */
	@Note("already closed PreparedStatement after execution")
	@Note("already closed PreparedStatement when throwing exception")
	@Note("already closed Connection when throwing exception")
	@Throws(at = "JDBCTool.executeUpdate(PreparedStatement)", value = "ErrorCode1.CODE_ERROR_108", when = "PreparedStatement.executeUpdate()")
	@ReturnNotNull
	public static int executeUpdate(@CanNotNull final Connection connection, @CanNotNull final PreparedStatement ps, //
			@CanNull final Handler beforeCloseConnection, //
			@CanNull final Consumer<RuntimeException> afterCloseConnection) {
		try {
			return executeUpdate(ps);
		} catch (final RuntimeException e) {
			throw closeConnectionAndThrowException(connection, beforeCloseConnection, afterCloseConnection, e);
		}
	}

}
